<?php

// Namespace

namespace Loop;


/**
 * @package		Loop
 * @category	Class
 */

class CSdkFactory
{
	/** 
	 * Generate an sdk
	 *
	 * @param 	string 	$extensionId 	The extension id
	 * @param 	string 	$className 		The className
	 *
	 * @required $extensionId
	 * @required $className
	 */

	public function api_generate()
	{
		// Get variables

		$extensionId = fv('extensionId', true);
		$className = fv('className', true);


		// Call api

		$result = $this->generate($extensionId, $className);
	}



	/** 
	 * Generate an sdk
	 *
	 * @param 	string 	$extensionId 	The extension id
	 * @param 	string 	$className 		The className
	 */

	public function generate($extensionId, $className)
	{
		// Default type

		$typeObject = 'Class';


		// Is this a class or a model ?

		$pathToClass = app()->getPathHelper()->getPathToClass($className, $extensionId);

		if (is_null($pathToClass) === true)
		{
			// It's not a class, maybe it's a model

			$pathToClass = app()->getPathHelper()->getPathToModel($className, $extensionId);


			// Change the type

			$typeObject = 'Model';
		}

		// Is there a path ?

		if (is_null($pathToClass) === true)
		{
			// No !!

			e(EXCEPTION_FILE_NOT_FOUND);
		}


		// Get path to the file

		$pathTofile = path
		(
			array
			(
				PATH_TEMPORARY,
				'SDK',
				$extensionId,
				$typeObject
			),
			true
		);


		// Dependencies

		require_once($pathToClass);


		//

		$objectName = $className;


		// Does the class exists ?

		if (class_exists($objectName) === false)
		{
			$objectName = str_replace('-', '\\', $extensionId) . '\\' . $objectName;
		}


		// Instanciate

		$object =  new $objectName();


		//

		$pathTofilePhp = $pathTofile . strtolower(substr($className, 1)) . '.php';
		$pathTofileDocHtml = $pathTofile . strtolower(substr($className, 1)) . 'Documentation.html';		


		$headerCode = $this->getHeaderCode($className);
		$proxyCode = $this->getProxyCode();
		$httpHelperCode = $this->getHttpHelperCode($className);
		$apiDetails = $this->getApiCode($extensionId, $typeObject, $className);

		$content = 
"<?php 
" . $headerCode . $proxyCode . $apiDetails['apiCode'] . $httpHelperCode . "
?>";

		file_put_contents($pathTofilePhp, $content);


		// Generate the documentation

		$this->generateDocumentation($className, $apiDetails['apiDocumentation'], $pathTofileDocHtml);


		return ;
	}


	/**
	 * Generate the html documentation
	 *
	 * @param string $documentationAPI 		The html documentation
	 * @param string $pathToFile 			The path to the html file
	 */

	private function generateDocumentation($className, $documentationAPI, $pathTofile)
	{
		// Get the style sheets

		$urisOfStylesheets = pref('[Loop]/views/urisOfStylesheets');
		$sheet = '';

		if (is_array($urisOfStylesheets) === true)
		{
			foreach ($urisOfStylesheets as $uriOfStylesheet)
			{
				$sheet .= '<link rel="stylesheet" type="text/css" href="' . url($uriOfStylesheet) . '" />';
			}
		}


		// Construct html

		$documentation = 
'
<html>
	<head>
	' . $sheet  .'
	</head>
	<body>
		<div class="container" style="font-size: 13px; line-height: 19px;">
			<h4 style="text-align: center;">
				' . $className . ' 
			</h4>
			<br />

			' . $documentationAPI. '
		</div>
	</body>
</html>';


		// Generate the file

		file_put_contents($pathTofile, $documentation);
	}


	/**
	 * Get the apis details for construct the sdk and the documentation
	 *
	 * @param 	string 	$extensionId 	The extensionId
	 * @param 	string 	$typeObject  	The type (Class, Model ...)
	 * @param 	string 	$className 		The class name
	 *
	 * @return 	array 	An associative array apiCode and apiDocumentation
	 */

	private function processApis($extensionId, $typeObject, $className)
	{
		$apiDetails = app()->getApiManager()->getApis($extensionId, $className, $typeObject);


		// 

		$apiCode = '';


		// Create array for documentation

		$docApi['API'] = array();


		// For each arguments found

		foreach ($apiDetails[$typeObject] as $apiNames => $apiDetails)
		{
			// For each api 

			foreach($apiDetails as $apiName => $details)
			{

				// Set infos for the doc

				$docApi['API'][$apiName]['description']['infos'] = $details['infos'];
				$docApi['API'][$apiName]['description']['return'] = $details['return'];
				$docApi['API'][$apiName]['description']['params'] = $details['arguments'];
				$docApi['API'][$apiName]['description']['richDocumentation'] = app()->getRichDocumentationManager()->getRichDocumentation($typeObject, $extensionId, $className, $apiName);


				// Order the arguments by isRequired

				$arguments = app()->getArrayHelper()->orderByKey($details['arguments'], 'isRequired', SORT_DESC, true);


				//

				$argumentsFragments = array();
				$variablesFragments = array();


				// For each argument

				foreach ($arguments as $argumentName => $argumentsDetails)
				{
					if (isset($argumentsDetails['defaultValue']) === true)
					{
						$argumentsFragments[] = $argumentName . ' = ' . $argumentsDetails['defaultValue'];
					}
					else
					{
						$argumentsFragments[] = $argumentName;
					}

					$variablesFragments[] = '\'' . substr($argumentName, 1) . '\' => ' . $argumentName;
				}


				// Construct the name of the function

				$functionName = substr($apiName, 4);


				// Is there arguments ?

				if (count($argumentsFragments) > 0)
				{
					// Get the type of call
					
					if (empty($details['call']) === false)
					{
						$call = 'call' . ucfirst(trim($details['call']));	
					}
					else
					{
						$call = 'callApi';
					}
					
					
					// Constrcut the call
					
					$apiCode .= 
'	' . $details['comment'] . '

	public static function ' . $functionName . '(' . implode(', ',  $argumentsFragments) . ')
	{

		// Build the URL and variables

		$uri = \'' . substr($className, 1) .  '.' . $functionName . '\';

		$variables = array
		(
			' . implode(', 
			', $variablesFragments) . '
		);


		// Call the API

		$result = ' . $className . 'HttpHelper::' . $call . '($uri, $variables);


		return $result;
	}


' ;				
				}		
			}			
		}


		// Generate the documentation html

		$documentation = app()->getDocumentationHelper()->generateHtmlAPI($docApi, false);



		return array
		(
			'apiCode' => $apiCode,
			'apiDocumentation' => $documentation
		);
	}


	/**
	 * Get the apis code for the proxy and the documentation
	 *
	 * @return 	array 	An associative array apiCode and apiDocumentation
	 */

	private function getApiCode($extensionId, $typeObject, $className)
	{
		$apiDetails = $this->processApis($extensionId, $typeObject, $className) ;


		// Create the definition of the class

		$apiCode =
'
/**
 *
 */

class ' . $className . 'ApiProxy
{

' . $apiDetails['apiCode'] . '

}
';

		return array
		(
			'apiCode' => $apiCode,
			'apiDocumentation' => $apiDetails['apiDocumentation']
		);

	}


	/**
	 * Get the code of the http helper
	 *
	 * @return string The  hhtp helper code
	 */

	private function getHttpHelperCode($className)
	{
		$httpHelperCode =
		'
/**
 *
 */

class ' . $className . 'HttpHelper
{
	/**
	 *
	 */

	public static function buildUrl($uri, $variables = array())
	{
		// Create the URL

		$url = pref(\'urlOf' . substr($className, 1) . '\') . $uri;

		$separator = \'?\';

		if (is_array($variables) == true)
		{
			foreach($variables as $variableName => $variableValue)
			{
				$url .= $separator . $variableName . \'=\' . urlencode($variableValue);
				$separator = \'&\';
			}
		}

		$url .= $separator . \'key=\' . pref(\'apiKey\'); 


		return $url;
	}


	/**
	 *
	 */

	public static function callAction($uri, $variables = array())
	{
		// Build the URL

		$url = ' . $className . 'HttpHelper::buildUrl(\'action/\' . $uri, $variables);


		// Redirect to the URL

		header(\'Location: \' . $url);
		die;
	}


	/**
	 *
	 */

	public static function callApi($uri, $variables = array())
	{
		// Build the URL

		$url = ' . $className . 'HttpHelper::buildUrl(\'api/json/\' . $uri);


		// Prepare variables

		$variables[\'key\'] = pref(\'apiKey\');

		foreach ($variables as $key => $variable)
		{
			if (is_null($variable))
			{		
				unset($variables[$key]);
			}
		}


		return ' . $className . 'HttpHelper::post($url, $variables);
	}


	/**
	 *
	 */

	public static function callApis($apis = array())
	{
		// Build the URL

		$url = ' . $className . 'HttpHelper::buildUrl(\'api/json/' . substr($className, 1) . '.callApis\');


		// Prepare variables

		$variables[\'apis\'] = $apis;
		$variables[\'key\'] = pref(\'apiKey\');

		
		return ' . $className . 'HttpHelper::post($url , $variables);
	}


	/**
	 *
	 */

	public static function post($url, $variables = null)
	{
		// Initialize cURL

		$cUrl = curl_init();

		curl_setopt($cUrl, CURLOPT_URL, $url);						// The Url
		curl_setopt($cUrl, CURLOPT_RETURNTRANSFER, true); 			// Return the result rather than display it
		curl_setopt($cUrl, CURLOPT_HEADER, false);					// Don\'t include headers in the result
		curl_setopt($cUrl, CURLOPT_POST, true);						// POST the query

		if (is_array($variables) == true)
		{
			foreach ($variables as $variableName => &$variableValue)
			{
				if (is_array($variableValue) === true)
				{
					$variableValue = json_encode($variableValue);
				}
			}

			curl_setopt($cUrl, CURLOPT_POSTFIELDS, $variables);		// POST variables
		}

			
		// Execute the query

		$rawResult = curl_exec($cUrl);

				
		// Close the HTTP query

		curl_close($cUrl);


		// Did we get an exception?

		if ($rawResult === false)
		{
			$result = new stdClass();

			$result->errorTitle = str(EXCEPTION_' . strtoupper(substr($className, 1)) . '_HTTP_QUERY_FAILED);
			$result->errorDescription = str(EXCEPTION_' . strtoupper(substr($className, 1)) . '_HTTP_QUERY_FAILED . \'?description\');
			$result->rawResult = $rawResult;
			$result->url = $url;
			$result->variables = $variables;

			return $result;
		}

		
		// Convert the result into JSON
		
		$result = json_decode($rawResult);

				
		// Did the conversion go well?

		if (json_last_error() !== JSON_ERROR_NONE)
		{
			$result = new stdClass();

			$result->errorTitle = str(EXCEPTION_' . strtoupper(substr($className, 1)) . '_JSON_DECODE_FAILED);
			$result->errorDescription = str(EXCEPTION_' . strtoupper(substr($className, 1)) . '_JSON_DECODE_FAILED . \'?description\');
			$result->rawResult = $rawResult;
			$result->url = $url;
			$result->variables = $variables;

			return $result;
		}


		return $result;		
	}
}
		
		';


		return $httpHelperCode;
	}


	/**
	 * Get the code of the header
	 *
	 * @return string The header code
	 */

	private function getHeaderCode($className)
	{
		$headerCode = 
		'
// Exceptions

$e = -1;

define(\'EXCEPTION_' . strtoupper(substr($className, 1)) . '_HTTP_QUERY_FAILED\', $e--);
define(\'EXCEPTION_' . strtoupper(substr($className, 1)) . '_JSON_DECODE_FAILED\', $e--);

		';


		return $headerCode;
	}


	/**
	 * Get the code of proxy functions
	 *
	 * @return string The proxy code
	 */

	private function getProxyCode()
	{
		$proxyCode = 
		'
/**
 *
 */

function pref($preferenceName, $preferenceValue = null)
{
	global $PREFS;

	if (empty($preferenceValue) === true)
	{
		if (isset($PREFS[$preferenceName]) == true)
		{
			return $PREFS[$preferenceName];
		}
	}
	else
	{
		$PREFS[$preferenceName] = $preferenceValue;
	}
}


/**
 *
 */

function str($stringName, $stringValue = null)
{
	global $STRINGS;

	if (empty($stringValue) === true)
	{
		if (isset($STRINGS[$stringName]) == true)
		{
			return $STRINGS[$stringName];
		}
		else
		{
			return $stringName;
		}
	}
	else
	{
		$STRINGS[$stringName] = $stringValue;
	}
}


/**
 *
 */

function url()
{
	// Define the scheme
				
	if 
	( 
		(isset($_SERVER[\'HTTPS\']) == false) || 
		(is_null($_SERVER[\'HTTPS\']) == true)
	)
	{
		$url = \'http://\';
	}
	else
	{
		$url = \'https://\';
	}
				
				
	// Add the host

	$url .= $_SERVER[\'SERVER_NAME\'];

				
	// Add the port

	if ($_SERVER[\'SERVER_PORT\'] != \'80\')
	{
		$url .= \':\' . $_SERVER[\'SERVER_PORT\'];
	}


	// Add the trailing slash

	$url .= \'/\';


	return $url;
}
		';


		return $proxyCode;
	}
}

?>